#include "clip_rect.h"
#include "stdlib.h"

/** @brief constructor
 * @param HWND hWnd
 * @note
 */
ClipRect::ClipRect(HWND hWnd)
{
    rect.x0=0;
    rect.y0 =0;
    rect.x1 =0;
    rect.y1 =0;

    next =0;
    prev =0;

    this->hWnd =hWnd;
}

/** @brief constructor
 * @param Rect *r
 * @note
 */
ClipRect::ClipRect(Rect *r)
{
    rect.x0 =r->x0;
    rect.x1 =r->x1;
    rect.y0 =r->y0;
    rect.y1 =r->y1;

    prev=next =0;
    this->hWnd =0;
}

/** @brief destructor
 * @note
 */
ClipRect::~ClipRect()
{
}

void ClipRect::operator delete(void *t)
{
    port_free(t);
}

void *ClipRect::operator new(unsigned int len)
{
   return port_malloc(len);
}

/**
 * @param short x_offset
 * @paramshort y_offset
 * @note
 */
void ClipRect::setPosition(short x_offset, short y_offset)
{
    rect.x0 +=x_offset;
    rect.x1 +=x_offset;
    rect.y0 +=y_offset;
    rect.y1 +=y_offset;
}

/**
 * @param short x
 * @param short y
 * @return int
 * @note check if a point is in rect
 */
int ClipRect::isInRect(short x, short y)
{
    return (rect.x1>x) && (rect.x0<=x) && (rect.y1>y) && (rect.y0<=y);
}

/** 
 * @param const Rect *pNewRect
 * @return int
 * @note check if a new Rect overlap
 */
int ClipRect::isOverlap(const Rect *pNewRect)
{
    int t;
    t= (pNewRect->x0 >rect.x1) || (pNewRect->y0>rect.y1) || (pNewRect->x1<rect.x0) || (pNewRect->y1<rect.y0) ;
    return !t;
}

/** @brief constructor
 * @param Rect *intersectedRect
 * @param const Rect *pNewRect
 * @note cut out the overlapped rectangle
 */

int ClipRect::intersectRect(Rect *intersectedRect, const Rect *pNewRect)
{
    intersectedRect->x0 = max(pNewRect->x0, rect.x0);
    intersectedRect->y0 = max(pNewRect->y0, rect.y0);
    intersectedRect->x1 = min(pNewRect->x1, rect.x1);
    intersectedRect->y1 = min(pNewRect->y1, rect.y1);

    return 1;
}

/** @brief On the top floor
 * @param const Rect *pRect
 * @note Repeat above shows the most
 */
int ClipRect::isOverCover(const Rect *pRect)
{
     return  (pRect->x0 <= rect.x0) && (pRect->y0<=rect.y0) &&(pRect->x1>=rect.x1) &&(pRect->y1>=rect.y1);
}

/** @brief the size is zero
 * @param const Rect *pRect
 * @return int
 * @note
 */
int ClipRect::isZeroSize(const Rect *pRect)
{
    return (pRect->x0 > pRect->x1) || (pRect->y0 >pRect->y1);
}

/** @brief Insert the rectangular list
 * @note
 */
void ClipRect::listInsert(ClipRect *list, ClipRect *items)
{
    ClipRect *next;

    if(items) return;
    if(list) return;
    
    next =list->next;

    list->next =items;
    items->prev =list;

    while(items->next) items=items->next;
    items->next =next;
    next->prev =items;
    
}

/** @brief remove new rect to a rect, and devided into 1/4/5 small rects
 * @param const Rect *pRect
 * @ret_val -# this:not overlap with this;\n
 *          -# 0: over cover this;\n
 *          -# a list of ClipRects: overlapped
 * @note 
 */
 ClipRect* ClipRect::removeRect(const Rect *pRect)
{
    Rect newRect;
    ClipRect *header, *t_pcr;

    //the new rect is zero size, return
    if( isZeroSize(pRect) )
        return this;

    //if the new rect is not colide with rect, return
    if( !isOverlap(pRect))
        return this;

    if(isOverCover(pRect))
    {
        return 0;
    }
    
    //clip the rect to fit to size
    intersectRect(&newRect, pRect);

    //create 4 clip rects , and add to link list
    header =0;
    if(pRect->y0 > rect.y0)
    {
         ClipRect *pNewRect;
       //top rect, zone 1
        pNewRect =new ClipRect(hWnd);
        pNewRect->rect.x0 = rect.x0;
        pNewRect->rect.x1 = rect.x1;
        pNewRect->rect.y0 = rect.y0;
        pNewRect->rect.y1 = pRect->y0;

        if(header)
        {
            t_pcr=header;
            while(t_pcr->next) t_pcr =t_pcr->next;
            t_pcr->next=pNewRect;
            pNewRect->prev =t_pcr;
        }
        else
        {
            header =pNewRect;
        }
    }
    
    if(pRect->x0 >rect.x0)
    {
        //zone 2
        ClipRect *pNewRect;
        pNewRect =new ClipRect(hWnd);
        pNewRect->rect.x0 = rect.x0;
        pNewRect->rect.x1 = pRect->x0;
        pNewRect->rect.y0 = pRect->y0;
        pNewRect->rect.y1 = pRect->y1;

        if(header)
        {
            t_pcr=header;
            while(t_pcr->next) t_pcr =t_pcr->next;
            t_pcr->next=pNewRect;
            pNewRect->prev =t_pcr;
        }
        else
        {
            header =pNewRect;
        }
    }
    
    if(pRect->x1 <rect.x1)
    {
        //zone 3
        ClipRect *pNewRect;
        pNewRect =new ClipRect(hWnd);
        pNewRect->rect.x0 = pRect->x1;
        pNewRect->rect.x1 = rect.x1;
        pNewRect->rect.y0 = pRect->y0;
        pNewRect->rect.y1 = pRect->y1;

        if(header)
        {
            t_pcr=header;
            while(t_pcr->next) t_pcr =t_pcr->next;
            t_pcr->next=pNewRect;
            pNewRect->prev =t_pcr;
        }
        else
        {
            header =pNewRect;
        }
    }
    if(pRect->y1 <rect.y1)
    {
        //zone 4
        ClipRect *pNewRect;
        pNewRect =new ClipRect(hWnd);
        pNewRect->rect.x0 = rect.x0;
        pNewRect->rect.x1 = rect.x1;
        pNewRect->rect.y0 = pRect->y1;
        pNewRect->rect.y1 = rect.y1;

        if(header)
        {
            t_pcr=header;
            while(t_pcr->next) t_pcr =t_pcr->next;
            t_pcr->next=pNewRect;
            pNewRect->prev =t_pcr;
        }
        else
        {
            header =pNewRect;
        }
    }

    return header;
}

/** 
 * @param const Rect *pRect
 * @return ClipRect*
 * @note unite a rect into list of clip rects
 */
ClipRect* ClipRect::uniteRect(const Rect *pRect)
{
    Rect newRect;

    if(isZeroSize(pRect))
        return this;

    if( !isOverlap(pRect))
        return this;

    intersectRect(&newRect, pRect);

    //melt into 1 rectangle
    if( (rect.x0 == newRect.x0) &&(rect.x1 == newRect.x1) )
    {
        //y melt
        rect.y0 = min(rect.y0, newRect.y0);
        rect.y1 = max(rect.y1, newRect.y1);
    }

    if( (rect.y0 == newRect.y0) && (rect.y1 ==newRect.y1))
    {
        //x melt
        rect.x0 = min(rect.x0, newRect.x0);
        rect.x1 = max(rect.x1, newRect.x1);
    }

    return this;

}


